﻿using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Threading;
using Csu.Modsim.NetworkUtils;
using ASquared;
using ASquared.ModelStatistics;

namespace iwpm.optimization
{
    public class HydroAnalyzer
    {
        private string _dir;
        private object _dblock = new object();
        private List<Matrix> _scenarios = new List<Matrix>();
        private List<string> _names = new List<string>();
        private int _numOfThreadsRunning; 
        private ManualResetEvent _handle = new ManualResetEvent(false);

        public HydroAnalyzer(string directory)
        {
            _dir = directory;
            if (!_dir.EndsWith("\\"))
                _dir += "\\";
        }

        public void Read()
        {
            if (!Directory.Exists(_dir))
            {
                Console.WriteLine("Directory " + _dir + " does not exist.");
                return;
            }

            // Get all the output files within the directory
            string[] files = Directory.GetFiles(_dir, "*OUTPUT.mdb", SearchOption.TopDirectoryOnly);
            _numOfThreadsRunning = files.Length; 
            ThreadPool.SetMaxThreads(3, 5);

            // Read all the files into memory
            for (int i = 0; i < files.Length; i++)
            {
                string flname = Convert.ToString(files[i]);
                Action wrappedAction = () => { try { ReadSingle(flname); } finally { } };
                ThreadPool.QueueUserWorkItem(x => wrappedAction());
            }

            // Wait until they finish 
            if (files.Length > 0)
                _handle.WaitOne(); 
        }

        public void WriteAnalysis()
        {
            WriteAnalysis(_dir + "analysis.csv");
        }

        public void WriteAnalysis(string file)
        {
            StreamWriter sw = new StreamWriter(file);
            sw.WriteLine("Name," + ModelPerformance.SingleLineStringHeader(","));
            for (int i = 0; i < _scenarios.Count; i++)
            {
                Matrix m = _scenarios[i];
                ModelPerformance perf = new ModelPerformance(m.GetCol(2).To1DArray(), m.GetCol(3).To1DArray());
                sw.WriteLine(_names[i] + "," + perf.ToSingleLineString(","));
            }
            sw.Close();
        }

        private void ReadSingle(string mdbfile)
        {
            string flname;
            flname = Path.GetFileName(mdbfile);
            try
            {
                Console.WriteLine("Reading output from " + flname);
                DBUtil db = new DBUtil(mdbfile, true, ",", false, MSType.Access);
                db.Open();
                DataTable dt = db.GetTable("SELECT * FROM HydroTargetOutput", "HydroTargets");
                if (dt == null)
                    throw new Exception("HydroTargetOutput not found.");
                lock (_dblock)
                {
                    _scenarios.Add(new Matrix(dt));
                    _names.Add(flname);
                }
                db.Close();
            }
            catch (Exception ex)
            {
                lock (_dblock)
                {
                    Console.WriteLine("Attempt to read output from " + flname + " failed:\n" + ex.ToString());
                }
            }
            finally
            {
                if (Interlocked.Decrement(ref _numOfThreadsRunning) == 0)
                    _handle.Set(); 
            }
        }
    }
}
